﻿/* ***** BEGIN LICENSE BLOCK *****
 *
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 * 
 * The Original Code is CnCNet Client code, Released 2nd January 2009.
 * 
 * The Initial Developers of the Original Code are
 * Adam Krock and John Sanderson. Portions created by
 * the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s): Adam Krock, John Sanderson.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 * 
 * ***** END LICENSE BLOCK *****/

using System;
using System.Net;
using System.Runtime.InteropServices;

namespace CnCNet
{
    public class cncNetcodec
    {
        #region Structures

        public class packets
        {
            public static readonly int CLIENT_PACKET = 17970176;
            public static readonly int SERVER_PACKET = 1192961;
            public static readonly int REPLY_PACKET = 34747393;
            public static readonly ushort INFO_END = 43521;

			// String structure with byte header/length
			public struct pString
			{
				public byte myLength;
				public string myString;
				
				public pString(byte l, string s)
				{
					myLength = l;
					myString = s;
				}
			}
			
			// Basic packet class
			public class packet
			{
				protected byte[] packetData = new byte[0];
                protected System.IO.MemoryStream packetStream;
                protected System.IO.BinaryReader packetReader;
				
                public packet()
                {
                }
							
				// Adds a value to the packetData
				private void addValue(byte[] b)
				{
					// Copy old array
					byte[] tempOne = packetData;
					// Resize array to fit new value
					packetData = new byte[tempOne.Length + b.Length];
					// copy old values to the new array
						// If this is not first value, copy
					if(tempOne.Length > 0)
					{
						// Copy old set
						Array.Copy(tempOne, packetData, tempOne.Length);
						// Add new set to end				
						int tempTwo = 0;
							// Starting at end of current array
						for(int i=tempOne.Length;i<packetData.Length;i++)
						{
							// Copy contents from b to the end of packetData
							packetData[i] = b[tempTwo];
							tempTwo++;
						}
					}
					else
					{
						// If this is first value, copy byte directly to data
						packetData = b;
					}
				}
							
				// Add methods
				public void addByte(byte b)
				{
					addValue(new byte[]{b});
				}
				
				public void addShort(short s)
				{			
					addValue(BitConverter.GetBytes(s));
				}
				
				public void addUShort(ushort us)
				{
					addValue(BitConverter.GetBytes(us));
				}
				
				public void addInt(int i)
				{
					addValue(BitConverter.GetBytes(i));
				}
				
				public void addUInt(uint ui)
				{
					addValue(BitConverter.GetBytes(ui));
				}
				
				public void addLong(long l)
				{
					addValue(BitConverter.GetBytes(l));
				}
				
				public void addULong(ulong ul)
				{
					addValue(BitConverter.GetBytes(ul));
				}
				
				public void addString(string s)
				{
					if(byte.MaxValue > s.Length)
					{
					addByte((byte)s.Length);
					addValue(System.Text.ASCIIEncoding.ASCII.GetBytes(s));
					}
				}
				
				public void addZeroBytes(byte length)
				{
					for(int i=0;i< length;i++)
					{
						addByte(0);
					}
				}

                public void addBytes(byte[] b)
                {
                    for (int i = 0; i < b.Length; i++)
                    {
                        addByte(b[i]);
                    }
                }
				
				// Get methods		
				public byte getByte()
				{
					return packetReader.ReadByte();
				}
				
				public short getShort()
				{
					return packetReader.ReadInt16();
				}
				
				public ushort getUShort()
				{
					return packetReader.ReadUInt16();
				}
				
				public int getInt()
				{
					return packetReader.ReadInt32();
				}
				
				public uint getUInt()
				{
					return packetReader.ReadUInt32();
				}
				
				public long getLong()
				{
					return packetReader.ReadInt64();
				}
				
				public ulong getULong()
				{
					return packetReader.ReadUInt64();
				}
				
				public pString getString()
				{
					byte tempOne = getByte();
					byte[] tempTwo = packetReader.ReadBytes(tempOne);
					string tempThree = System.Text.ASCIIEncoding.ASCII.GetString(tempTwo);
					return new pString(tempOne,tempThree);
				}
				
				public byte[] getBytes()
				{
					return packetData;
				}
			}
			
			
            // New packet revisions

            public class rawCncPacketTest : packet
            {
                // IP
                public byte IPVerLen;
                public byte IPTOS;
                public short IPLength;
                public short IPID;
                public short IPOffset;
                public byte IPTTL;
                public byte IPProtocol;
                public short IPChecksum;
                public int IPSrcAddr;
                public int IPDestAddr;
                // UDP
                public ushort UDPsourcePort;
                public ushort UDPdestPort;
                public ushort UDPLength;
                public ushort UDPcheckSum;
                // CNC
                public int CNCpacketDirection;
                public int CNCpacketNumber;
                public int CNCpacketSource;
                public int CNCpacketDest;
                public short CNCpacketPort;
                public short CNCpacketHeaderEnd;
                // Data
                public byte dataType; // 1
                public pString dataSender; // 12
                public pString dataMessage; // 24
                public int dataPackOne;
                public int dataPackTwo;
                public byte dataPackEnd;

                public rawCncPacketTest(byte[] packet)
                {
                    // Start with empty array
                    packetData = packet;
                    // Assign reference for memory reader
                    packetStream = new System.IO.MemoryStream(packetData);
                    // Assing reference for Binary reader
                    packetReader = new System.IO.BinaryReader(packetStream);
                    // IP Header section
                    IPVerLen = getByte();
                    IPTOS = getByte();
                    IPLength = getShort();
                    IPID = getShort();
                    IPOffset = getShort();
                    IPTTL = getByte();
                    IPProtocol = getByte();
                    IPChecksum = getShort();
                    IPSrcAddr = getInt();
                    IPDestAddr = getInt();
                    // UDP header section
                    UDPsourcePort = getUShort();
                    UDPdestPort = getUShort();
                    UDPLength = getUShort();
                    UDPcheckSum = getUShort();
                    // CNC header section
                    CNCpacketDirection = getInt();
                    CNCpacketNumber = getInt();
                    CNCpacketSource = getInt();
                    CNCpacketDest = getInt();
                    CNCpacketPort = getShort();
                    CNCpacketHeaderEnd = getShort();
                    // Data section
                    dataType = getByte();
                    dataSender = getString();
                    dataMessage = getString();
                    dataPackOne = getInt();
                    dataPackTwo = getInt();
                    dataPackEnd = getByte();
                }
            }

            public class broadCastOne : packet
            {
                public int packetType;
                public int packetNumber;
                public int packetSource;
                public int packetDestination;
                public short packetPort;
                public ushort packetInfoEnd;

                public broadCastOne(int number)
                {
                    addInt(CLIENT_PACKET);
                    addInt(number);
                    addInt(-1);
                    addInt(-1);
                    addShort(-1);
                    addUShort(INFO_END);
                    addByte(0);
                    addZeroBytes(45);
                    //addString("This is a test");
                }

                public broadCastOne(byte[] b)
                {
                    // Start with empty array
                    packetData = b;
                    // Assign reference for memory reader
                    packetStream = new System.IO.MemoryStream(packetData);
                    // Assing reference for Binary reader
                    packetReader = new System.IO.BinaryReader(packetStream);
                    packetType = getInt();
                    packetNumber = getInt();
                    packetSource = getInt();
                    packetDestination = getInt();
                    packetPort = getShort();
                    packetInfoEnd = getUShort();
                }
            }

            public class broadCastTwo : packet
            {
                public int packetType; //4
                public int packetNumber; //4
                public int packetSource; //4
                public int packetDestination; //4
                public short packetPort; // 2
                public ushort packetInfoEnd; // 2
                public byte dataId; // 1
                public string dataName; // 11 length

                public broadCastTwo(int number, string serverName)
                {
                    addInt(CLIENT_PACKET);
                    addInt(number);
                    addInt(-1);
                    addInt(-1);
                    addShort(-1);
                    addUShort(INFO_END);
                    addZeroBytes(46);
                }

                public broadCastTwo(byte[] b)
                {
                    // Start with empty array
                    packetData = b;
                    // Assign reference for memory reader
                    packetStream = new System.IO.MemoryStream(packetData);
                    // Assing reference for Binary reader
                    packetReader = new System.IO.BinaryReader(packetStream);
                    packetType = getInt();
                    packetNumber = getInt();
                    packetSource = getInt();
                    packetDestination = getInt();
                    packetPort = getShort();
                    packetInfoEnd = getUShort();
                }
            }

            public class decode
            {

                // Unified C&C95 Header + Data
                // For attempted efficiency
                // IP Header
                // UDP header
                // CNC header
                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                public struct rawCncPacket
                {
                    // IP
                    public byte IPVerLen;
                    public byte IPTOS;
                    public short IPLength;
                    public short IPID;
                    public short IPOffset;
                    public byte IPTTL;
                    public byte IPProtocol;
                    public short IPChecksum;
                    public int IPSrcAddr;
                    public int IPDestAddr;
                    // UDP
                    public ushort UDPsourcePort;
                    public ushort UDPdestPort;
                    public ushort UDPLength;
                    public ushort UDPcheckSum;
                    // CNC
                    public int CNCpacketDirection;
                    public int CNCpacketNumber;
                    public int CNCpacketSource;
                    public int CNCpacketDest;
                    public short CNCpacketPort;
                    public short CNCpacketHeaderEnd;
                    // Data
                    public byte dataType; // 1
                    public byte[] dataSenderBytes;
                    public string dataSender; // 12
                    public byte[] dataMessageBytes;
                    public string dataMessage; // 24
                    public int dataPackOne;
                    public int dataPackTwo;
                    public byte dataPackEnd;

                    public rawCncPacket(byte[] packet)
                    {
                        // IP Header section
                        System.IO.MemoryStream stm = new System.IO.MemoryStream(packet, 0, 94);
                        System.IO.BinaryReader rdr = new System.IO.BinaryReader(stm);
                        IPVerLen = rdr.ReadByte();
                        IPTOS = rdr.ReadByte();
                        IPLength = rdr.ReadInt16();
                        IPID = rdr.ReadInt16();
                        IPOffset = rdr.ReadInt16();
                        IPTTL = rdr.ReadByte();
                        IPProtocol = rdr.ReadByte();
                        IPChecksum = rdr.ReadInt16();
                        IPSrcAddr = rdr.ReadInt32();
                        IPDestAddr = rdr.ReadInt32();
                        // UDP header section
                        UDPsourcePort = rdr.ReadUInt16();
                        UDPdestPort = rdr.ReadUInt16();
                        UDPLength = rdr.ReadUInt16();
                        UDPcheckSum = rdr.ReadUInt16();
                        // CNC header section
                        CNCpacketDirection = rdr.ReadInt32();
                        CNCpacketNumber = rdr.ReadInt32();
                        CNCpacketSource = rdr.ReadInt32();
                        CNCpacketDest = rdr.ReadInt32();
                        CNCpacketPort = rdr.ReadInt16();
                        CNCpacketHeaderEnd = rdr.ReadInt16();
                        // Data section
                        dataType = rdr.ReadByte();
                        dataSenderBytes = rdr.ReadBytes(12);
                        dataMessageBytes = rdr.ReadBytes(24);
                        dataSender = System.Text.ASCIIEncoding.ASCII.GetString(dataSenderBytes);                      
                        dataMessage = System.Text.ASCIIEncoding.ASCII.GetString(dataMessageBytes);
                        dataPackOne = rdr.ReadInt32();
                        dataPackTwo = rdr.ReadInt32();
                        dataPackEnd = rdr.ReadByte();
                    }
                }


                public class rawCncPacketTest : packet
                {
                    // IP
                    public byte IPVerLen;
                    public byte IPTOS;
                    public short IPLength;
                    public short IPID;
                    public short IPOffset;
                    public byte IPTTL;
                    public byte IPProtocol;
                    public short IPChecksum;
                    public int IPSrcAddr;
                    public int IPDestAddr;
                    // UDP
                    public ushort UDPsourcePort;
                    public ushort UDPdestPort;
                    public ushort UDPLength;
                    public ushort UDPcheckSum;
                    // CNC
                    public int CNCpacketDirection;
                    public int CNCpacketNumber;
                    public int CNCpacketSource;
                    public int CNCpacketDest;
                    public short CNCpacketPort;
                    public short CNCpacketHeaderEnd;
                    // Data
                    public byte dataType; // 1
                    public pString dataSender; // 12
                    public pString dataMessage; // 24
                    public int dataPackOne;
                    public int dataPackTwo;
                    public byte dataPackEnd;

                    public rawCncPacketTest(byte[] packet)
                    {
                        // Start with empty array
                        packetData = packet;
                        // Assign reference for memory reader
                        packetStream = new System.IO.MemoryStream(packetData);
                        // Assing reference for Binary reader
                        packetReader = new System.IO.BinaryReader(packetStream);
                        // IP Header section
                        IPVerLen = getByte();
                        IPTOS = getByte();
                        IPLength = getShort();
                        IPID = getShort();
                        IPOffset = getShort();
                        IPTTL = getByte();
                        IPProtocol = getByte();
                        IPChecksum = getShort();
                        IPSrcAddr = getInt();
                        IPDestAddr = getInt();
                        // UDP header section
                        UDPsourcePort = getUShort();
                        UDPdestPort = getUShort();
                        UDPLength = getUShort();
                        UDPcheckSum = getUShort();
                        // CNC header section
                        CNCpacketDirection = getInt();
                        CNCpacketNumber = getInt();
                        CNCpacketSource = getInt();
                        CNCpacketDest = getInt();
                        CNCpacketPort = getShort();
                        CNCpacketHeaderEnd = getShort();
                        // Data section
                        dataType = getByte();
                        dataSender = getString();
                        dataMessage = getString();
                        dataPackOne = getInt();
                        dataPackTwo = getInt();
                        dataPackEnd = getByte();
                    }
                }

                // CNC DATA
                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                public struct cncData
                {
                    public byte[] packetData;

                    public cncData(byte[] packet, ushort length)
                    {
                        System.IO.MemoryStream stm = new System.IO.MemoryStream(packet, 28, (length-8));
                        System.IO.BinaryReader rdr = new System.IO.BinaryReader(stm);
                        packetData = rdr.ReadBytes((length-8));
                    }
                }

                // CNC DATA
                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                public struct cncDosboxData
                {
                    public byte[] packetData;

                    public cncDosboxData(byte[] packet, short length)
                    {
                        System.IO.MemoryStream stm = new System.IO.MemoryStream(packet, 58, (length - 8));
                        System.IO.BinaryReader rdr = new System.IO.BinaryReader(stm);
                        packetData = rdr.ReadBytes((length - 8));
                    }
                }

                // C&C95 LOBBY PACKET (GENERIC)
                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                public struct lobbyPacket
                {
                    public int packetDirection;
                    public int packetNumber;
                    public int packetSource;
                    public int packetDest;
                    public short packetPort;
                    public long packetDataOne;
                    public long packetDataTwo;
                    public long packetDataThree;
                    public long packetDataFour;
                    public long packetDataFive;
                    public long packetDataSix;

                    public lobbyPacket(byte[] packet)
                    {
                        System.IO.MemoryStream stm = new System.IO.MemoryStream(packet, 28, 66);
                        System.IO.BinaryReader rdr = new System.IO.BinaryReader(stm);
                        packetDirection = rdr.ReadInt32();
                        packetNumber = rdr.ReadInt32();
                        packetSource = rdr.ReadInt32();
                        packetDest = rdr.ReadInt32();
                        packetPort = rdr.ReadInt16();
                        packetDataOne = rdr.ReadInt64();
                        packetDataTwo = rdr.ReadInt64();
                        packetDataThree = rdr.ReadInt64();
                        packetDataFour = rdr.ReadInt64();
                        packetDataFive = rdr.ReadInt64();
                        packetDataSix = rdr.ReadInt64();
                    }
                }

                //02
                //Repeats server name back to server (verification?)
                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                public struct broadCastTwo
                {
                    public int packetDirection;
                    public int packetNumber;
                    public int packetSource;
                    public int packetDest;
                    public short packetPort;
                    public short packetHeaderEnd;
                    public byte packetDataId;
                    public byte[] packerDataName;

                    public broadCastTwo(byte[] packet)
                    {
                        System.IO.MemoryStream stm = new System.IO.MemoryStream(packet, 28, 32);
                        System.IO.BinaryReader rdr = new System.IO.BinaryReader(stm);
                        packetDirection = rdr.ReadInt32();
                        packetNumber = rdr.ReadInt32();
                        packetSource = rdr.ReadInt32();
                        packetDest = rdr.ReadInt32();
                        packetPort = rdr.ReadInt16();
                        packetHeaderEnd = rdr.ReadInt16();
                        packetDataId = rdr.ReadByte();
                        packerDataName = rdr.ReadBytes(11);
                    }
                }

                //04
                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                public struct joinRequest
                {
                    public int packetDirection;
                    public int packetNumber;
                    public int packetSource;
                    public int packetDest;
                    public short packetPort;
                    public short packetHeaderEnd;
                    public byte packetDataId;
                    public byte[] packerDataName;
                    public string packetDataNameString;
                    public byte packetDataSide;
                    public byte packetDataColour;

                    public joinRequest(byte[] packet)
                    {
                        System.IO.MemoryStream stm = new System.IO.MemoryStream(packet, 28, 35);
                        System.IO.BinaryReader rdr = new System.IO.BinaryReader(stm);
                        packetDirection = rdr.ReadInt32();
                        packetNumber = rdr.ReadInt32();
                        packetSource = rdr.ReadInt32();
                        packetDest = rdr.ReadInt32();
                        packetPort = rdr.ReadInt16();
                        packetHeaderEnd = rdr.ReadInt16();
                        packetDataId = rdr.ReadByte();
                        packerDataName = rdr.ReadBytes(11);
                        packetDataNameString = System.Text.ASCIIEncoding.ASCII.GetString(packerDataName);
                        rdr.ReadByte();
                        packetDataSide = rdr.ReadByte();
                        packetDataColour = rdr.ReadByte();
                    }
                }

                //10
                [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
                public struct messagePacket
                {
                    public int packetDirection;
                    public int packetNumber;
                    public int packetSource;
                    public int packetDest;
                    public short packetPort;
                    public short packetEnd;
                    public byte dataType; // 1
                    public byte[] dataSenderBytes;
                    public string dataSender; // 12
                    public byte[] dataMessageBytes;
                    public string dataMessage; // 24
                    public int dataPackOne;
                    public int dataPackTwo;
                    public byte dataPackEnd;

                    public messagePacket(byte[] packet)
                    {
                        System.IO.MemoryStream stm = new System.IO.MemoryStream(packet, 28, 66);
                        System.IO.BinaryReader rdr = new System.IO.BinaryReader(stm);
                        packetDirection = rdr.ReadInt32();
                        packetNumber = rdr.ReadInt32();
                        packetSource = rdr.ReadInt32();
                        packetDest = rdr.ReadInt32();
                        packetPort = rdr.ReadInt16();
                        packetEnd = rdr.ReadInt16();
                        dataType = rdr.ReadByte();
                        dataSenderBytes = rdr.ReadBytes(12);
                        dataMessageBytes = rdr.ReadBytes(24);
                        dataSender = System.Text.ASCIIEncoding.ASCII.GetString(dataSenderBytes);
                        dataMessage = System.Text.ASCIIEncoding.ASCII.GetString(dataMessageBytes);
                        dataPackOne = rdr.ReadInt32();
                        dataPackTwo = rdr.ReadInt32();
                        dataPackEnd = rdr.ReadByte();
                    }
                }

                // INGAME PACKET
                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                public struct gamePacket
                {
                    public int packetId;
                    public int packetNumber;
                    public byte dataType;
                    public short dataNumber;
                    public byte dataInfoOne;
                    public short dataLocation;
                    public int dataScenario;
                    public short dataInfoTwo;
                    public byte dataPackEnd;

                    public gamePacket(byte[] packet)
                    {
                        System.IO.MemoryStream stm = new System.IO.MemoryStream(packet, 28, 21);
                        System.IO.BinaryReader rdr = new System.IO.BinaryReader(stm);
                        packetId = rdr.ReadInt32();
                        packetNumber = rdr.ReadInt32();
                        dataType = rdr.ReadByte();
                        dataNumber = rdr.ReadInt16();
                        dataInfoOne = rdr.ReadByte();
                        dataLocation = rdr.ReadInt16();
                        dataScenario = rdr.ReadInt32();
                        dataInfoTwo = rdr.ReadInt16();
                        dataPackEnd = rdr.ReadByte();
                    }
                }
                
            }
			
            public class encode
            {
                



                public class natPmpPacket : packet
                {
                    public byte version;
                    public byte opCode;
                    public ushort reserved;
                    public ushort internalPort;
                    public ushort externalPort;
                    public uint duration;

                    public natPmpPacket(byte v, byte oCe, ushort r, ushort iPort, ushort ePort, uint d)
                    {
                        addByte(v);
                        addByte(oCe);
                        addUShort(r);
                        addUShort(iPort);
                        addUShort(ePort);
                        addUInt(d);
                    }
                }


                #region Lobby

                

                //Encoding
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 75, CharSet = CharSet.Ansi)]
                public struct cncChatPacket
                {
                    public int packetType; //4
                    public int packetNumber; //4
                    public int packetSource; //4
                    public int packetDestination; //4
                    public short packetPort; // 2
                    public ushort packetInfoEnd; // 2
                    public byte dataId; // 1
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 36)]
                    public string data;

                    public cncChatPacket(string text)
                    {
                        packetType = CLIENT_PACKET;
                        packetNumber = 0;
                        packetSource = -1;
                        packetDestination = -1;
                        packetPort = -1;
                        packetInfoEnd = INFO_END;
                        dataId = 75;
                        data = text;
                    }
                }




                // Reply packet
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 20, CharSet = CharSet.Ansi)]
                public struct confirmationPacket
                {
                    public int packetType; //4
                    public int packetNumber; //4
                    public int packetSource; //4
                    public int packetDestination; //4
                    public short packetPort; // 2
                    public ushort packetInfoEnd; // 2

                    public confirmationPacket(int dst, short port, int number)
                    {
                        // Put in network order to avoid conversion overhead
                        packetType = REPLY_PACKET;
                        packetNumber = number;
                        packetSource = 0;
                        packetDestination = dst;
                        packetPort = port;
                        packetInfoEnd = INFO_END;
                    }
                }

				
                // Initial broadcast


                // 01
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 66, CharSet = CharSet.Ansi)]
                public struct broadCastReplyOne
                {
                    public int packetType; //4
                    public int packetNumber; //4
                    public int packetSource; //4
                    public int packetDestination; //4
                    public short packetPort; // 2
                    public ushort packetInfoEnd; // 2
                    public byte dataId; // 1
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
                    public string dataName;
                    public short dataPadOne;
                    public uint dataPadTwo;
                    public int dataPadThree;
                    public int dataPadFour;
                    public int dataPadFive;
                    public int dataPadSix;
                    public uint dataPadSeven;
                    public int dataPadEight;
                    public uint dataPadNine;

                    public broadCastReplyOne(int number, int dst, short port, string name, bool compat)
                    {
                        packetType = SERVER_PACKET;
                        packetNumber = number;
                        packetSource = 0;
                        packetDestination = dst;
                        packetPort = IPAddress.HostToNetworkOrder(port);
                        packetInfoEnd = INFO_END;
                        dataId = 1;
                        dataName = name;
                        if (compat)
                        {
                            dataPadOne = 359; // 615 for non-compat mode
                        }
                        else
                        {
                            dataPadOne = 615;
                        }
                        dataPadTwo = 3976200192;
                        dataPadThree = 7;
                        dataPadFour = 446169088;
                        dataPadFive = 443023444;
                        dataPadSix = 446169172;
                        dataPadSeven = 3989569620;
                        dataPadEight = 447086599;
                        dataPadNine = 3698851924;
                    }

                }

                // 03
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 66, CharSet = CharSet.Ansi)]
                public struct broadCastReplyTwo
                {
                    public int packetType; //4
                    public int packetNumber; //4
                    public int packetSource; //4
                    public int packetDestination; //4
                    public short packetPort; // 2
                    public ushort packetInfoEnd; // 2
                    public byte dataId; // 1
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
                    public string dataName;
                    public byte dataPadOne;
                    public byte dataSide;
                    public int dataColour;
                    public int dataPadThree;
                    public int dataPadFour;
                    public int dataPadFive;
                    public int dataPadSix;
                    public uint dataPadSeven;
                    public int dataPadEight;
                    public uint dataPadNine;

                    public broadCastReplyTwo(int number, int src, int dst, short port, string name, byte side, int colour)
                    {
                        packetType = SERVER_PACKET;
                        packetNumber = number;
                        packetSource = src;
                        packetDestination = dst;
                        packetPort = IPAddress.HostToNetworkOrder(port);
                        packetInfoEnd = INFO_END;
                        dataId = 3;
                        dataName = name;
                        dataPadOne = 0;
                        dataSide = side;
                        dataColour = colour; 
                        dataPadThree = 40087;
                        dataPadFour = 446169088;
                        dataPadFive = 443023444;
                        dataPadSix = 446169172;
                        dataPadSeven = 3989569620;
                        dataPadEight = 447086599;
                        dataPadNine = 3698851924;
                    }

                    public broadCastReplyTwo(int number, int dst, short port, string name, byte side, int colour)
                    {
                        packetType = SERVER_PACKET;
                        packetNumber = number;
                        packetSource = 0;
                        packetDestination = dst;
                        packetPort = IPAddress.HostToNetworkOrder(port);
                        packetInfoEnd = INFO_END;
                        dataId = 3;
                        dataName = name;
                        dataPadOne = 0;
                        dataSide = side;
                        dataColour = colour;
                        dataPadThree = 40087;
                        dataPadFour = 446169088;
                        dataPadFive = 443023444;
                        dataPadSix = 446169172;
                        dataPadSeven = 3989569620;
                        dataPadEight = 447086599;
                        dataPadNine = 3698851924;
                    }
                }

                // 05 
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 66, CharSet = CharSet.Ansi)]
                public struct joinRequestReply
                {
                    public int packetType; //4
                    public int packetNumber; //4
                    public int packetSource; //4
                    public int packetDestination; //4
                    public short packetPort; // 2
                    public ushort packetInfoEnd; // 2
                    public byte dataId; // 1
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
                    public string dataName;
                    public byte dataPadOne;
                    public byte dataSide;
                    public byte dataColour;

                    public joinRequestReply(int number, int dst, short port, string name, byte side, byte colour)
                    {
                        packetType = SERVER_PACKET;
                        packetNumber = number;
                        packetSource = 0;
                        packetDestination = dst;
                        packetPort = IPAddress.HostToNetworkOrder(port);
                        packetInfoEnd = INFO_END;
                        dataId = 5;
                        dataName = name;
                        dataPadOne = 0;
                        dataSide = side;
                        dataColour = colour;
                    }
                }

                // 07
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 66, CharSet = CharSet.Ansi)]
                public struct settings
                {
                    public int packetType; //4
                    public int packetNumber; //4
                    public int packetSource; //4
                    public int packetDestination; //4
                    public short packetPort; // 2
                    public ushort packetInfoEnd; // 2
                    public byte dataId; // 1
                    public long dataPadOne; // 8
                    public int dataPadTwo; // 4
                    public byte gameScenario; // 1
                    public int gameCredits; //4
                    public int gameMode; // 4
                    public byte gameTechLevel; // 1
                    public byte gameUnitCount; // 1
                    public int gameUniqueID; // 4
                    public byte gameStaticOne; // 1 (0x21)
                    public byte gameCtfEnable; // 1 (0x01=ON/0x00=OFF)
                    public byte gameTiberium; // 1 (0x38=ON/0x20=OFF)
                    public short gameSettingsEnd; // 2


                    public settings(int number, int dst, short port, byte scenario, byte units, byte tech, int credits,
                        bool bases, bool tiberium, bool crates, bool ai, bool ctf)
                    {
                        
                        // Put in network order to avoid conversion overhead
                        packetType = SERVER_PACKET;
                        packetNumber = number;
                        packetSource = 0;
                        packetDestination = dst;
                        packetPort = IPAddress.HostToNetworkOrder(port);
                        packetInfoEnd = INFO_END;
                        dataId = 7;
                        dataPadOne = 0;
                        dataPadTwo = 0;
                        // Start of settings
                        gameScenario = scenario;
                        gameCredits = credits;
                        gameMode = 0;
                        gameTechLevel = tech;
                        gameUnitCount = units;
                        gameUniqueID = 2366;
                        gameStaticOne = 33;
                        gameCtfEnable = 0;
                        gameTiberium = 32;
                        gameSettingsEnd = 578;
                        //8= AI
                        //4= crates
                        //2= tib
                        //1= bases
                        if (ai)
                        {
                            gameMode = gameMode | 8;
                        }
                        if (crates)
                        {
                            gameMode = gameMode | 4;
                        }
                        if (tiberium)
                        {
                            gameMode = gameMode | 2;
                            gameTiberium = 56;
                        }
                        if (bases)
                        {
                            gameMode = gameMode | 1;
                        }
                        if (ctf)
                        {
                            gameCtfEnable = 1;
                        }                                     
                    }
                }


                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 66, CharSet = CharSet.Ansi)]
                public struct gameStart
                {
                    public int packetType; //4
                    public int packetNumber; //4
                    public int packetSource; //4
                    public int packetDestination; //4
                    public short packetPort; // 2
                    public ushort packetInfoEnd; // 2
                    public byte dataId; // 1
                    public byte dataPadOne;
                    public int dataPadTwo;
                    public int dataPadThree;
                    public int dataLaunch;

                    public gameStart(int dst, short port, int number, int playerCount)
                    {
                        packetType = SERVER_PACKET;
                        packetNumber = number;
                        packetSource = 0;
                        packetDestination = dst;
                        packetPort = port;
                        packetInfoEnd = INFO_END;
                        dataId = 09;
                        dataPadOne = 0;
                        dataPadTwo = 0;
                        dataPadThree = 0;
                        dataLaunch = IPAddress.HostToNetworkOrder(playerCount);
                    }
                }

                // 10
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 66, CharSet = CharSet.Ansi)]
                public struct chat
                {

                    public int packetType; //4
                    public int packetNumber; //4
                    public int packetSource; //4
                    public int packetDestination; //4
                    public short packetPort; // 2
                    public ushort packetInfoEnd; // 2
                    public byte dataId; // 1
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)]
                    public string dataSender; // 11
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)]
                    public string dataMessage; // 23
                    public ushort dataPart; // 2
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
                    public string dataEndCodeOne; // 4
                    public byte dataIsInLength;
                    public int dataEndCodeTwo; // 4

                    public chat(int dst, short port, string sender, string message)
                    {
                        packetType = 1192961;
                        packetNumber = 0;
                        packetSource = 0;
                        packetDestination = IPAddress.HostToNetworkOrder(dst);
                        packetPort = IPAddress.HostToNetworkOrder(port);
                        packetInfoEnd = INFO_END;
                        dataId = 10;                 
                        dataSender = sender;
                        dataMessage = message;
                        dataPart = 64206;
                        dataEndCodeOne = new string(new char[] { message[0], message[1] });
                        if (message.Length > 2)
                        {
                            dataIsInLength = 81;
                        }
                        else
                        {
                            dataIsInLength = 65;
                        }
                        dataEndCodeTwo = 1221;
                    }
                }

                // 11
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 66, CharSet = CharSet.Ansi)]
                public struct inGameKeepAlive
                {

                    public int packetType; //4
                    public int packetNumber; //4
                    public int packetSource; //4
                    public int packetDestination; //4
                    public short packetPort; // 2
                    public ushort packetInfoEnd; // 2
                    public byte dataId; // 1

                    public inGameKeepAlive(int dst, short port, int number)
                    {
                        packetType = SERVER_PACKET;
                        packetNumber = number;
                        packetSource = 0;
                        packetDestination = dst;
                        packetPort = IPAddress.HostToNetworkOrder(port);
                        packetInfoEnd = INFO_END;
                        dataId = 11;
                    }

                    public inGameKeepAlive(int src, int dst, short port, int number)
                    {
                        packetType = SERVER_PACKET;
                        packetNumber = number;
                        packetSource = src;
                        packetDestination = dst;
                        packetPort = IPAddress.HostToNetworkOrder(port);
                        packetInfoEnd = INFO_END;
                        dataId = 11;
                    }
                }


                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                public struct clientRegistration
                {
                    public byte packetId;
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
                    public string senderName; // 11
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
                    public string senderPassword; // 11         
                    public short senderPort;

                    public clientRegistration(string name, string password, string ip, short port)
                    {
                        packetId = 117;
                        senderName = name;
                        senderPassword = password;
                        senderPort = port;
                    }
                }


                #endregion


                #region Game


                // Generic
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 21, CharSet = CharSet.Ansi)]
                public struct gamePacket
                {
                    public int packetId;
                    public int packetNumber;
                    public byte dataType;
                    public short dataNumber;
                    public byte dataInfoOne; // 0
                    public short dataLocation;
                    public int dataScenario;
                    public short dataInfoTwo; // 0
                    public byte dataPackEnd; // 2


                    public gamePacket(int id, int number, byte type, short dNumber, byte infoOne, short location, int scenario, short infoTwo, byte dataEnd)
                    {
                        packetId = id;
                        packetNumber = number;
                        dataType = type;
                        dataNumber = dNumber;
                        dataInfoOne = infoOne;
                        dataLocation = location;
                        dataScenario = scenario;
                        dataInfoTwo = infoTwo;
                        dataPackEnd = dataEnd;
                    }

                }


                // 14
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 21, CharSet = CharSet.Ansi)]
                public struct startPosition
                {
                    public int packetId;
                    public int packetNumber;
                    public byte dataType;
                    public short dataNumber;
                    public byte dataInfoOne; // 0
                    public short dataLocation;
                    public int dataScenario;
                    public short dataInfoTwo; // 0
                    public byte dataPackEnd; // 2

                    
                    public startPosition(int id, int number, byte type, short dNumber, byte infoOne, short location, int scenario, short infoTwo, byte dataEnd)
                    {
                        packetId = id;
                        packetNumber = number;
                        dataType = type;
                        dataNumber = dNumber;
                        dataInfoOne = infoOne;
                        dataLocation = location;
                        dataScenario = scenario;
                        dataInfoTwo = infoTwo;
                        dataPackEnd = dataEnd;
                    }

                }

                // 17
                [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 21, CharSet = CharSet.Ansi)]
                public struct positionUpdate
                {
                    public int packetId;
                    public int packetNumber;
                    public byte dataType;
                    public short dataNumber;
                    public byte dataInfoOne; // 0
                    public short dataLocation;
                    public int dataScenario;
                    public short dataInfoTwo; // 0
                    public byte dataPackEnd; // 2


                    public positionUpdate(int id, int number, byte type, short dNumber, byte infoOne, short location, int scenario, short infoTwo, byte dataEnd)
                    {
                        packetId = id;
                        packetNumber = number;
                        dataType = type;
                        dataNumber = dNumber;
                        dataInfoOne = infoOne;
                        dataLocation = location;
                        dataScenario = scenario;
                        dataInfoTwo = infoTwo;
                        dataPackEnd = dataEnd;
                    }

                }

                #endregion
            }
        }

        #endregion
    }
}